#include "inputfilestream.h"

obj::inputfilestream::inputfilestream(const std::string& file, unsigned int buffersize) : ifs(file.c_str()), buffersize(buffersize),
readingbuffer(buffersize), restorebuffer(buffersize), source(&inputfilestream::fromReadingBuffer) {
    if (ifs.is_open())
        read();
    else
        throw;
}

obj::inputfilestream::~inputfilestream() {
    ifs.close();
}

char obj::inputfilestream::next() {
    return (this->*source)();
}

void obj::inputfilestream::restore(char c) {
    unsigned insertpos = restorebuffer.cursor + restorebuffer.length;

    if (insertpos >= restorebuffer.buf.size())
        restorebuffer.increase();

    restorebuffer.buf[insertpos] = c;
    ++restorebuffer.length;

    source = &inputfilestream::fromRestoreBuffer;
}

bool obj::inputfilestream::eof() {
    if (restorebuffer.length > 0)
        return false;
    
    if (readingbuffer.cursor == readingbuffer.length)
        read();
    return (readingbuffer.length == 0);
}

void obj::inputfilestream::read() {
    if (ifs.eof())
        readingbuffer.length = 0;
    else {
        ifs.read(&readingbuffer.buf[0], buffersize);
        readingbuffer.length = ifs.gcount();
    }

    readingbuffer.cursor = 0;
}

char obj::inputfilestream::fromReadingBuffer() {
    return readingbuffer.next();
}

char obj::inputfilestream::fromRestoreBuffer() {
    char c = restorebuffer.buf[restorebuffer.cursor++];
    --restorebuffer.length;

    if (restorebuffer.length == 0) {
        restorebuffer.cursor = 0;
        source = &inputfilestream::fromReadingBuffer;
    }

    return c;
}

